#include "StdAfx.h"
#include "FileDeviceHandleLibrary.h"

namespace ja2{ namespace vfs
{
	FileDeviceHandleLibrary::FileDeviceHandleLibrary(std::ifstream &Stream, std::string const &Name, long long Begin, long long End)
		: FileDeviceHandle(Name, Name), m_BeginPos(Begin), m_EndPos(End), m_ActualPosition(0), m_Stream(Stream)
	{
	}

	std::streamsize FileDeviceHandleLibrary::read(char *Buffer, std::streamsize Size)
	{
		// Must seek to right position, because stream is shared
		seek(m_ActualPosition);
		// If we want to read outside of file, try to read as much as possible
		if((m_BeginPos + m_ActualPosition + long long(Size)) > m_EndPos)
			Size = m_EndPos - (m_BeginPos + m_ActualPosition);
		// Return value
		std::streamsize ret = (Size == 0 ? -1 : Size);
		// Try to read if we have somethin to read
		if(Size > 0)
		{
			// Read from stream failed
			if(!m_Stream.read(Buffer, Size))
			{
				// We haven't read all
				if((ret = m_Stream.gcount()) != Size)
					JA2_ASSERT(false);
			}
			// Update actual position
			m_ActualPosition += Size;
		}

		return ret;
	}
	
	std::streamsize FileDeviceHandleLibrary::write(const char* /*Buffer*/, std::streamsize /*Size*/)
	{
		throw UnimplementedException(__FUNC__);
	}
	
	boost::iostreams::stream_offset FileDeviceHandleLibrary::seek(boost::iostreams::stream_offset Offset, std::ios_base::seekdir Direction)
	{
		boost::iostreams::stream_offset new_offset = Offset;
		switch(Direction)
		{
		case std::ios_base::cur:
			new_offset = m_ActualPosition + Offset;
			break;
		case std::ios_base::end:
			new_offset = m_EndPos - Offset;
			break;
			// Do nothing
		default:
			break;
		}
		// Do actaul seek
		seek(new_offset);
		// Save new position
		m_ActualPosition = new_offset;

		return m_ActualPosition;
	}

	void FileDeviceHandleLibrary::open(std::ios_base::openmode /*Mode*/)
	{
		// Do nothing as file can't be opened
	}
	
	bool FileDeviceHandleLibrary::is_open() const
	{
		// Library file should be opened already, no need to open
		assert(!m_Stream.fail() && m_Stream.is_open());

		return true;
	}
	
	void FileDeviceHandleLibrary::close()
	{
		// Can be closed
	}

	void FileDeviceHandleLibrary::seek(long long Position)
	{
		// If we are trying to read before begin or beyond end of file
		if(m_BeginPos + Position < m_BeginPos || m_BeginPos + Position > m_EndPos)
			throw std::runtime_error((boost::format(resources::FILE_TRYING_TO_READ_OUTSIDE_OF_FILE) % get_real_name()).str());
		// Move in stream
		m_Stream.seekg(m_BeginPos + Position, std::ios_base::beg);
	}
} /*vfs*/} /*ja2*/